package com.system.module.tool.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.ServiceException;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.util.StringUtil;
import com.system.common.constant.Constants;
import com.system.common.constant.GenConstants;
import com.system.common.core.text.CharsetKit;
import com.system.common.exception.BaseException;
import com.system.common.exception.CustomException;
import com.system.common.utils.SecurityUtils;
import com.system.common.utils.StringUtils;
import com.system.common.utils.sql.SqlGeneratorUtils;
import com.system.framework.config.GenConfig;
import com.system.framework.handler.TransHandler;
import com.system.framework.web.domain.BaseEntity;
import com.system.framework.web.domain.BasicEntity;
import com.system.module.tool.entity.GenCreateTableRecord;
import com.system.module.tool.entity.GenSysMenu;
import com.system.module.tool.entity.GenTable;
import com.system.module.tool.entity.GenTableColumn;
import com.system.module.tool.mapper.GenCreateTableRecordMapper;
import com.system.module.tool.mapper.GenSysMenuMapper;
import com.system.module.tool.mapper.GenTableColumnMapper;
import com.system.module.tool.mapper.GenTableMapper;
import com.system.module.tool.request.CreateTableRequest;
import com.system.module.tool.request.FieldRequest;
import com.system.module.tool.request.GenCodeDeployRequest;
import com.system.module.tool.response.TableListResponse;
import com.system.module.tool.util.GenUtils;
import com.system.module.tool.util.VelocityInitializer;
import com.system.module.tool.util.VelocityUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.jdbc.ScriptRunner;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.sql.DataSource;
import javax.sql.rowset.serial.SerialException;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 业务 服务层实现
 *
 * @author 程序员Mars
 */
@Service
public class GenTableServiceImpl implements IGenTableService {
    private static final Logger log = LoggerFactory.getLogger(GenTableServiceImpl.class);

    @Resource
    private DataSource dataSource;

    @Resource
    private GenTableMapper genTableMapper;

    @Resource
    private GenTableColumnMapper genTableColumnMapper;

    @Resource
    private GenSysMenuMapper genSysMenuMapper;

    @Resource
    private GenCreateTableRecordMapper createTableRecordMapper;

    @Resource
    private GenConfig genConfig;

    public static final String SRC = "/src";

    @Resource
    private GenUtils genUtils;

    /**
     * 查询业务信息
     *
     * @param id 业务ID
     * @return 业务信息
     */
    @Override
    public GenTable selectGenTableById(Long id) {
        GenTable genTable = genTableMapper.selectGenTableById(id);
        setTableFromOptions(genTable);
        return genTable;
    }

    /**
     * 查询业务列表
     *
     * @param genTable 业务信息
     * @return 业务集合
     */
    @Override
    public List<GenTable> selectGenTableList(GenTable genTable) {
        return genTableMapper.selectGenTableList(genTable);
    }

    /**
     * 查询据库列表
     *
     * @param genTable 业务信息
     * @return 数据库表集合
     */
    @Override
    public List<GenTable> selectDbTableList(GenTable genTable) {
        return genTableMapper.selectDbTableList(genTable);
    }

    /**
     * 查询据库列表
     *
     * @param tableNames 表名称组
     * @return 数据库表集合
     */
    @Override
    public List<GenTable> selectDbTableListByNames(String[] tableNames) {
        return genTableMapper.selectDbTableListByNames(tableNames);
    }

    /**
     * 修改业务
     *
     * @param genTable 业务信息
     * @return 结果
     */
    @Override
    @Transactional
    public void updateGenTable(GenTable genTable) {
        String options = JSON.toJSONString(genTable.getParams());
        genTable.setOptions(options);
        int row = genTableMapper.updateGenTable(genTable);
        if (row > 0) {
            for (GenTableColumn cenTableColumn : genTable.getColumns()) {
                genTableColumnMapper.updateGenTableColumn(cenTableColumn);
            }
        }
    }

    /**
     * 删除业务对象
     *
     * @param tableIds 需要删除的数据ID
     * @return 结果
     */
    @Override
    @Transactional
    public void deleteGenTableByIds(Long[] tableIds) {
        genTableMapper.deleteGenTableByIds(tableIds);
        genTableColumnMapper.deleteGenTableColumnByIds(tableIds);
    }

    /**
     * 导入表结构
     *
     * @param tableList 导入表列表
     */
    @Override
    @Transactional
    public void importGenTable(List<GenTable> tableList) {
        String operName = SecurityUtils.getUsername();
        try {
            for (GenTable table : tableList) {
                String tableName = table.getTableName();
                genUtils.initTable(table, operName);
                int row = genTableMapper.insertGenTable(table);
                if (row > 0) {
                    // 保存列信息
                    List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
                    for (GenTableColumn column : genTableColumns) {
                        GenUtils.initColumnField(column, table);
                        genTableColumnMapper.insertGenTableColumn(column);
                    }
                }
            }
        } catch (Exception e) {
            throw new CustomException("导入失败：" + e.getMessage());
        }
    }

    /**
     * 预览代码
     *
     * @param tableId 表编号
     * @return 预览数据列表
     */
    @Override
    public Map<String, String> previewCode(Long tableId) {
        Map<String, String> dataMap = new LinkedHashMap<>();
        // 查询表信息
        GenTable table = genTableMapper.selectGenTableById(tableId);
        // 查询列信息
        List<GenTableColumn> columns = table.getColumns();
        setPkColumn(table, columns);
        setGenBaseField(table);
        VelocityInitializer.initVelocity();

        VelocityContext context = VelocityUtils.prepareContext(table);

        // 获取模板列表
        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
        for (String template : templates) {
            // 渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, Constants.UTF8);
            tpl.merge(context, sw);
            dataMap.put(template, sw.toString());
        }
        return dataMap;
    }

    /**
     * 生成代码
     *
     * @param tableName 表名称
     * @return 数据
     */
    @Override
    public byte[] generatorCode(String tableName) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);
        generatorCode(tableName, zip);
        IOUtils.closeQuietly(zip);
        return outputStream.toByteArray();
    }

    /**
     * 批量生成代码
     *
     * @param tableNames 表数组
     * @return 数据
     */
    @Override
    public byte[] generatorCode(String[] tableNames) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);
        for (String tableName : tableNames) {
            generatorCode(tableName, zip);
        }
        IOUtils.closeQuietly(zip);
        return outputStream.toByteArray();
    }

    /**
     * 查询表信息并生成代码
     */
    private void generatorCode(String tableName, ZipOutputStream zip) {
        // 查询表信息
        GenTable table = genTableMapper.selectGenTableByName(tableName);
        // 查询列信息
        List<GenTableColumn> columns = table.getColumns();
        setPkColumn(table, columns);

        VelocityInitializer.initVelocity();

        VelocityContext context = VelocityUtils.prepareContext(table);

        // 获取模板列表
        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
        for (String template : templates) {
            // 渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, Constants.UTF8);
            tpl.merge(context, sw);
            try {
                // 添加到zip
                zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table)));
                IOUtils.write(sw.toString(), zip, Constants.UTF8);
                IOUtils.closeQuietly(sw);
                zip.flush();
                zip.closeEntry();
            } catch (IOException e) {
                log.error("渲染模板失败，表名：" + table.getTableName(), e);
            }
        }
    }

    /**
     * 修改保存参数校验
     *
     * @param genTable 业务信息
     */
    @Override
    public void validateEdit(GenTable genTable) {
        if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) {
            String options = JSON.toJSONString(genTable.getParams());
            JSONObject paramsObj = JSONObject.parseObject(options);
            if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE))) {
                throw new CustomException("树编码字段不能为空");
            } else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_PARENT_CODE))) {
                throw new CustomException("树父编码字段不能为空");
            } else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_NAME))) {
                throw new CustomException("树名称字段不能为空");
            }
        }
    }


    /**
     * 设置主键列信息
     *
     * @param table 业务表信息
     */
    public void setPkColumn(GenTable table) {
        for (GenTableColumn column : table.getColumns()) {
            if (column.isPk()) {
                table.setPkColumn(column);
                break;
            }
        }
        if (StringUtils.isNull(table.getPkColumn())) {
            table.setPkColumn(table.getColumns().get(0));
        }
        if (GenConstants.TPL_SUB.equals(table.getTplCategory())) {
            for (GenTableColumn column : table.getSubTable().getColumns()) {
                if (column.isPk()) {
                    table.getSubTable().setPkColumn(column);
                    break;
                }
            }
            if (StringUtils.isNull(table.getSubTable().getPkColumn())) {
                table.getSubTable().setPkColumn(table.getSubTable().getColumns().get(0));
            }
        }
    }

    /**
     * 设置主子表信息
     *
     * @param table 业务表信息
     */
    public void setSubTable(GenTable table) {
        String subTableName = table.getSubTableName();
        if (StringUtils.isNotEmpty(subTableName)) {
            table.setSubTable(genTableMapper.selectGenTableByName(subTableName));
        }
    }


    /**
     * 生成代码（自定义路径）
     * ITKEY自定义方法 2022年4月5日
     *
     * @param tableName 表名称
     * @param genPath   生成的路径
     */
    public void generatorCode(String tableName, String genPath) {
        // 查询表信息
        GenTable table = genTableMapper.selectGenTableByName(tableName);
        // 设置主子表信息
        setSubTable(table);
        // 设置主键列信息
        setPkColumn(table);
        // 设置是否生成基础字段
        setGenBaseField(table);

        //强制设置生成目录
        if (genPath != null && !"".equals(genPath)) {
            table.setGenType("1");
            table.setGenPath(genPath);
            //强制删除目录中之前的所有文件
            File genPathDir = new File(genPath);
            if (genPathDir.exists()) {
                if (genPathDir.isDirectory()) {
                    for (File f : Objects.requireNonNull(genPathDir.listFiles())) {
                        if (f.isDirectory()) {
                            try {
                                FileUtils.deleteDirectory(f);
                            } catch (IOException exception) {
                                exception.printStackTrace();
                            }
                        } else {
                            f.delete();
                        }
                    }
                }
            } else {
                //目录不存在，则创建目录
                genPathDir.mkdirs();
            }
        }
        // 设置菜单存放位置
        setMenuLocation(table);
        VelocityInitializer.initVelocity();
        VelocityContext context = VelocityUtils.prepareContext(table);
        // 获取模板列表
        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
        //是否输出所有文件，包含前端，后端
        for (String template : templates) {
            // 渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, Constants.UTF8);
            tpl.merge(context, sw);
            try {
                String path = getGenPath(table, template);
                FileUtils.writeStringToFile(new File(path), sw.toString(), CharsetKit.UTF_8);
            } catch (IOException e) {
                throw new BaseException("渲染模板失败，表名：" + table.getTableName());
            }
        }
    }

    /**
     * 设置是否生成基础字段
     *
     * @param table table
     */
    private void setGenBaseField(GenTable table) {
        List<GenCreateTableRecord> createTableRecords = createTableRecordMapper.selectList(Wrappers.lambdaQuery(GenCreateTableRecord.class)
                .eq(GenCreateTableRecord::getTableEnName, table.getTableName()).orderByDesc(BasicEntity::getCreateTime).last("limit 1"));
        if (!CollectionUtils.isEmpty(createTableRecords)) {
            Integer genBaseField = createTableRecords.get(0).getGenBaseField();
            if (genBaseField == 0) {
                // 生成基础字段 列信息去掉基础字段重新赋值
                List<GenTableColumn> columns = table.getColumns();
                Iterator<GenTableColumn> iterator = columns.iterator();
                while (iterator.hasNext()) {
                    GenTableColumn column = iterator.next();
                    if (Arrays.asList(GenConstants.COLUMNNAME_NOT_BASE_ENTITY).contains(column.getColumnName())) {
                        iterator.remove();
                    }
                }
                table.setColumns(columns);
                table.setGenBaseField(true);
            }
        } else {
            // 不生成基础字段 列信息去掉基础字段重新赋值
            boolean isGenBaseField = false;
            List<GenTableColumn> columns = table.getColumns();
            Iterator<GenTableColumn> iterator = columns.iterator();
            while (iterator.hasNext()) {
                GenTableColumn column = iterator.next();
                if (Arrays.asList(GenConstants.COLUMNNAME_NOT_LIST).contains(column.getColumnName()) && !column.getColumnName().equals("create_time")) {
                    isGenBaseField = true;
                    iterator.remove();
                }
            }
            table.setColumns(columns);
            table.setGenBaseField(isGenBaseField);
        }
    }


    private void setMenuLocation(GenTable table) {
        if (StringUtils.isNotEmpty(genConfig.getGenMenuId())) {
            table.setMenuId(Long.valueOf(genConfig.getGenMenuId()));
        } else {
            // 默认系统下面所有菜单
            table.setMenuId(3L);
        }
    }

    /**
     * 获取代码生成地址
     *
     * @param table    业务表信息
     * @param template 模板文件路径
     * @return 生成地址
     */
    public static String getGenPath(GenTable table, String template) {
        String genPath = table.getGenPath();
        if (StringUtils.equals(genPath, "/")) {
            return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table);
        }
        return genPath + "/" + VelocityUtils.getFileName(template, table);
    }


    @Override
    public void deploy(GenCodeDeployRequest request) {
        if (CollectionUtils.isEmpty(request.getTableName())) {
            throw new BaseException("请选择部署表结构");
        }
        // 生成代码的目录
        String generatorCodePath = genConfig.getGeneratorCodePath();
        // Java后台的Src目录
        String javaDir = genConfig.getServerCodeDir() + SRC;
        // Vue前端的Src目录
        String vueDir = genConfig.getVueCodeDir() + SRC;
        for (String tableName : request.getTableName()) {
            this.generatorCode(tableName, generatorCodePath);
            // 自动复制后台代码
            this.copyServerCode(generatorCodePath, javaDir);
            // 自动复制前台代码
            this.copyWebUiCode(generatorCodePath, vueDir);
            // 执行菜单SQL
            this.executeSql(generatorCodePath);
        }
    }

    /**
     * 后台代码复制
     *
     * @param generatorCodePath generatorCodePath
     * @param javaSrc           javaSrc
     */
    private void copyServerCode(String generatorCodePath, String javaSrc) {
        File srcFile = new File(generatorCodePath + "/" + "main");
        //复制到的目录
        File destFile = new File(javaSrc + "/" + "main");
        try {
            FileUtils.copyDirectory(srcFile, destFile);
            System.out.println("------后台代码构建成功--------");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 复制前端代码
     *
     * @param generatorCodePath generatorCodePath
     * @param vueSrc            vueSrc
     */
    private void copyWebUiCode(String generatorCodePath, String vueSrc) {
        File uiSrcFile = new File(generatorCodePath + "/" + "vue");
        //复制到的目录
        File uiDestFile = new File(vueSrc);
        try {
            FileUtils.copyDirectory(uiSrcFile, uiDestFile);
            System.out.println("------前端代码生成成功--------");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 执行sql文件
     *
     * @param generatorCodePath generatorCodePath
     */
    private void executeSql(String generatorCodePath) {
        // 自动执行菜单创建sql脚本
        String sqlFile = "";
        File dir = new File(generatorCodePath);
        if (dir.exists()) {
            if (dir.isDirectory()) {
                for (File f : Objects.requireNonNull(dir.listFiles())) {
                    //只处理.sql结尾的文件
                    if (f.getPath().endsWith(".sql")) {
                        sqlFile = f.getPath();
                        //目前的场景只处理一个sql文件就好了，理论上只会有一个sql
                        break;
                    }
                }
            }
        }
        //判断一下sql是否执行过，防止重复执行sql
        //读取sql文件的第3行，并用,拆分字符串
        if (!"".equals(sqlFile)) {
            //读取sql文本
            String sqlText = readFileText(sqlFile);
            //取第一条sql的values
            String keyText = sqlText.substring(sqlText.indexOf("values("), sqlText.indexOf("');"));
            String[] keyArray = keyText.split(",");
            if (keyArray.length >= 5) {
                String keyword = keyArray[4];
                if (keyword.length() >= 3) {
                    //去掉两边的''
                    keyword = keyword.substring(2, keyword.length() - 1);
                }
                //根据component字段查询，如果值已经存在则跳过执行sql
                GenSysMenu genSysMenu = new GenSysMenu();
                genSysMenu.setComponent(keyword);
                List<GenSysMenu> resultList = genSysMenuMapper.selectMenuList(genSysMenu);
                if (resultList != null && resultList.size() > 0) {
                    //已经有相关的菜单了，不在重复创建了
                    log.info("已创建菜单，请勿重复创建");
                } else {
                    log.info("正在执行创建菜单的sql");
                    String[] sqlFilePath = {sqlFile};
                    System.out.println(sqlFilePath[0]);
                    doExecuteSql(sqlFilePath);
                }
            }
        }
    }

    @Override
    public void remove(GenCodeDeployRequest request) {
        if (CollectionUtils.isEmpty(request.getTableName())) {
            throw new BaseException("请选择卸载表结构");
        }
        //生成代码的目录
        String generatorCodePath = genConfig.getGeneratorCodePath();
        //Java后台的Src目录
        String javaSrc = genConfig.getServerCodeDir() + SRC;
        //Vue前端的Src目录
        String vueSrc = genConfig.getVueCodeDir() + SRC;
        for (String tableName : request.getTableName()) {
            //生成当前模块的代码，用于后续的比较
            this.generatorCode(tableName, generatorCodePath);
            // 删除后台代码
            this.removeServerCode(generatorCodePath, javaSrc);
            //被复制的文件夹 自动复制前台代码
            String sqlFile = this.removeUiCode(generatorCodePath, vueSrc);
            // 执行删除语句 读取sql文件的第3行，并用,拆分字符串 判断一下sql是否执行过，防止重复执行sql
            this.executeRemoveSql(sqlFile);
        }
    }

    @Override
    public void createTable(CreateTableRequest request) throws SQLException {
        this.checkParams(request);
        // 根据英文名称查询数据库是否已存在改表
        List<TableListResponse> list = genTableMapper.selectDbTableListByTableNames(Collections.singletonList(request.getTableEnName()));
        if (!CollectionUtils.isEmpty(list)) {
            throw new ServiceException("当前表已创建");
        }
        // 创建表
        List<FieldRequest> fieldRequestList = request.getFieldRequestList().stream().peek(s -> {
            s.setFieldComment(s.getFieldName());
            String fieldName = s.getFieldName();
            if (isChinese(fieldName)) {
                String enFieldName = TransHandler.trans(fieldName);
                s.setFieldName(enFieldName);
            } else {
                s.setFieldName(fieldName);
                String chineseComment = TransHandler.trans(fieldName);
                s.setFieldComment(chineseComment);
            }
        }).collect(Collectors.toList());
        String tableDdl = SqlGeneratorUtils.generateDynamicSQL(fieldRequestList, request.getTableEnName(), request.isGenBaseField(), request.getTableName());
        // 执行建表语句
        this.doExecuteSqls(tableDdl);
        // 保存生成记录
        GenCreateTableRecord createTableRecord = new GenCreateTableRecord();
        createTableRecord.setTableEnName(request.getTableEnName());
        createTableRecord.setTableName(request.getTableName());
        boolean genBaseField = request.isGenBaseField();
        createTableRecord.setGenBaseField(genBaseField ? 0 : 1);
        createTableRecordMapper.insert(createTableRecord);
    }

    /**
     * 执行SQL脚本
     *
     * @param sql sql
     */
    public void doExecuteSqls(String sql) throws SQLException {
        Connection connection = DataSourceUtils.getConnection(dataSource);
        Statement statement = connection.createStatement();
        statement.execute(sql);
        statement.close();
        connection.close();
    }

    /**
     * 判断是否是中文
     *
     * @param str str
     * @return boolean
     */
    public static boolean isChinese(String str) {
        // 使用正则表达式匹配是否全为中文字符
        return str.matches("[\\u4E00-\\u9FA5]+");
    }


    /**
     * 参数校验
     *
     * @param request request
     * @throws SerialException
     */
    private void checkParams(CreateTableRequest request) throws SerialException {
        if (StringUtil.isEmpty(request.getTableName())) {
            throw new SerialException("表中文名称不能为空");
        }
        if (StringUtil.isEmpty(request.getTableEnName())) {
            throw new SerialException("表英文名称不能为空");
        }
        if (CollectionUtils.isEmpty(request.getFieldRequestList())) {
            throw new ServiceException("表字段不能为空");
        }
    }

    /**
     * 删除后台代码
     *
     * @param generatorCodePath generatorCodePath
     * @param javaSrc           javaSrc
     */
    private void removeServerCode(String generatorCodePath, String javaSrc) {
        File srcFile = new File(generatorCodePath + "/" + "main");
        //复制到的目录
        File destFile = new File(javaSrc + "/" + "main");

        //后端代码的文件列表
        List<String> javaSrcFileList = new ArrayList<>();
        try {
            System.out.println("------后台代码卸载成功--------");
            System.out.println("------java源码对照的文件夹--------" + srcFile.getPath());
            System.out.println("------卸载的项目路径--------" + destFile.getPath());
            //卸载后台代码
            //输出所有要删除的文件
            scanFile2List(srcFile, javaSrcFileList);
            System.out.println("-----------后端删除文件列表----------");
            for (String f : javaSrcFileList) {
                //相对路径
                String xdlj = f.substring(generatorCodePath.length(), f.length());
                //拼出项目中源码的绝对路径
                //拼出项目中源码的绝对路径
                String realJavaFileStr = javaSrc + xdlj;
                System.out.println(realJavaFileStr);
                File realJavaFile = new File(realJavaFileStr);
                realJavaFile.delete();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除前端代码
     *
     * @param generatorCodePath generatorCodePath
     * @param vueSrc            vueSrc
     * @return String
     */
    private String removeUiCode(String generatorCodePath, String vueSrc) {
        File uiSrcFile = new File(generatorCodePath + "/" + "vue");
        //复制到的目录
        File uiDestFile = new File(vueSrc);
        //前端代码的文件列表
        List<String> vueSrcFileList = new ArrayList<>();
        try {
            System.out.println("------UI代码复制成功--------");
            System.out.println("------vue源码对照的文件夹--------" + uiSrcFile.getPath());
            System.out.println("------卸载的项目路径--------" + uiDestFile.getPath());
            //卸载后台代码
            //输出所有要删除的文件
            scanFile2List(uiSrcFile, vueSrcFileList);
            System.out.println("-----------前端删除文件列表----------");
            for (String f : vueSrcFileList) {
                //相对路径
                String xdlj = f.substring(generatorCodePath.length() + 4, f.length());
                //拼出项目中源码的绝对路径
                String realVueFileStr = vueSrc + xdlj;
                System.out.println(realVueFileStr);
                File realVueFile = new File(realVueFileStr);
                realVueFile.delete();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //3自动执行菜单创建sql脚本
        String sqlFile = "";
        File dir = new File(generatorCodePath);
        if (dir.exists()) {
            if (dir.isDirectory()) {
                for (File f : Objects.requireNonNull(dir.listFiles())) {
                    //只处理.sql结尾的文件
                    if (f.getPath().endsWith(".sql")) {
                        sqlFile = f.getPath();
                        break;  //目前的场景只处理一个sql文件就好了，理论上只会有一个sql
                    }
                }
            }
        }
        return sqlFile;
    }

    private void executeRemoveSql(String sqlFile) {
        if (!"".equals(sqlFile)) {
            //读取sql文本
            String sqlText = readFileText(sqlFile);
            //取第一条sql的values
            String keyText = sqlText.substring(sqlText.indexOf("values("), sqlText.indexOf("');"));
            String[] keyArray = keyText.split(",");
            if (keyArray.length >= 5) {
                System.out.println("==============================");
                String keyword = keyArray[4];
                if (keyword.length() >= 3) {
                    //去掉两边的''
                    keyword = keyword.substring(2, keyword.length() - 1);
                }
                System.out.println("component:" + keyword);
                System.out.println("==============================");
                //根据component字段查询，如果值已经存在则跳过执行sql
                GenSysMenu genSysMenu = new GenSysMenu();
                genSysMenu.setComponent(keyword);
                List<GenSysMenu> resultList = genSysMenuMapper.selectMenuList(genSysMenu);
                if (resultList != null && resultList.size() > 0) {
                    //已经有相关的菜单了，准备卸载
                    System.out.println(resultList);
                    //获取所有子菜单的列表
                    for (GenSysMenu sm :
                            resultList) {
                        genSysMenu = new GenSysMenu();
                        genSysMenu.setParentId(sm.getMenuId());
                        List<GenSysMenu> sonList = genSysMenuMapper.selectMenuList(genSysMenu);
                        System.out.println(sonList);
                        //删除子菜单
                        for (GenSysMenu son :
                                sonList) {
                            System.out.println("-------删除子菜单-----MenuName:" + son.getMenuName() + "---MenuId:" + son.getMenuId());
                            genSysMenuMapper.deleteMenuById(son.getMenuId());
                        }
                        System.out.println("-------删除父菜单-----MenuName:" + sm.getMenuName() + "---MenuId:" + sm.getMenuId());
                        genSysMenuMapper.deleteMenuById(sm.getMenuId());
                    }
                }
            }
        }
    }

    /**
     * 扫描目录下
     *
     * @param file     目录路径
     * @param fileList 保存文件列表
     */
    public static void scanFile2List(File file, List<String> fileList) {
        // 当前的路径是一个目录
        if (file.isDirectory()) {
            File[] list = file.listFiles((f) -> f.isDirectory() || !f.isDirectory());
            for (File temp : list) {
                // 递归操作，继续列出
                scanFile2List(temp, fileList);
            }
        } else {
            fileList.add(file.getPath());
        }
    }

    /**
     * 使用ScriptRunner执行SQL脚本
     *
     * @param filePaths 是文件的绝对路径数组，格式如下：
     *                  String[] filePaths = {"/xxx/sql/update1.sql", "/xxx/sql/update2.sql"};
     */
    public void doExecuteSql(String[] filePaths) {
        //通过数据源获取数据库链接
        Connection connection = DataSourceUtils.getConnection(dataSource);
        //创建脚本执行器
        ScriptRunner scriptRunner = new ScriptRunner(connection);
        //创建字符输出流，用于记录SQL执行日志
        StringWriter writer = new StringWriter();
        PrintWriter print = new PrintWriter(writer);
        //设置执行器日志输出
        scriptRunner.setLogWriter(print);
        //设置执行器错误日志输出
        scriptRunner.setErrorLogWriter(print);
        //设置读取文件格式
        Resources.setCharset(StandardCharsets.UTF_8);

        for (String path : filePaths) {
            Reader reader = null;
            try {
                File file = new File(path);
                //获取资源文件的字符输入流
                if (file.exists()) {
                    reader = new FileReader(file);
                }
            } catch (IOException e) {
                //文件流获取失败，关闭链接
                log.error(e.getMessage(), e);
                scriptRunner.closeConnection();
                return;
            }
            //执行SQL脚本
            scriptRunner.runScript(reader);
            //关闭文件输入流
            try {
                reader.close();
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        }
        //输出SQL执行日志
        log.debug(writer.toString());
        //关闭输入流
        scriptRunner.closeConnection();
    }

    /**
     * 读取文本内容
     *
     * @param filePath 文件路径
     * @return String
     */
    public static String readFileText(String filePath) {
        File file = new File(filePath);
        BufferedReader reader = null;
        StringBuffer sb = new StringBuffer();
        try {
            reader = new BufferedReader(new FileReader(file));
            String tempStr;
            while ((tempStr = reader.readLine()) != null) {
                sb.append(tempStr).append("\n");
            }
            reader.close();
            return sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
        return sb.toString();
    }

    /**
     * 设置主键列信息
     *
     * @param table   业务表信息
     * @param columns 业务字段列表
     */
    public void setPkColumn(GenTable table, List<GenTableColumn> columns) {
        for (GenTableColumn column : columns) {
            if (column.isPk()) {
                table.setPkColumn(column);
                break;
            }
        }
        if (StringUtils.isNull(table.getPkColumn())) {
            table.setPkColumn(columns.get(0));
        }
    }

    /**
     * 设置代码生成其他选项值
     *
     * @param genTable 设置后的生成对象
     */
    public void setTableFromOptions(GenTable genTable) {
        JSONObject paramsObj = JSONObject.parseObject(genTable.getOptions());
        if (StringUtils.isNotNull(paramsObj)) {
            String treeCode = paramsObj.getString(GenConstants.TREE_CODE);
            String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE);
            String treeName = paramsObj.getString(GenConstants.TREE_NAME);
            genTable.setTreeCode(treeCode);
            genTable.setTreeParentCode(treeParentCode);
            genTable.setTreeName(treeName);
        }
    }
}
